<?php

namespace Lib;

final class Token {
    use \Lib\Traits\Instance;

    /**
     * @var string
     */
    private $_token = null;

    /**
     * @var \Lib\Std
     */
    private $_std = null;

    /**
     * 获取token
     *
     * @return string
     */
    public function get() {
        return $this->_token;
    }

    /**
     * 获取token对应的数据
     *
     * @return \Lib\Std
     */
    public function getStd() {
        return ( $this->_std ? : ( new \Lib\Std( [ ] ) ) );
    }

    /**
     * 生成 token
     *
     * @param array $data
     * @return boolean
     */
    public function built( array $data ) {
        $rkey  = \Lib\Consts::TOKEN_KEY;
        $reids = $this->getRedis();
        $token = md5( \Lib\Misc::randCode( 32 ) . uniqid( mt_rand( 1000, 9999 ) ) );
        $sign  = $this->signature( $token, $data );
        $reids->hMset( $rkey, array( $sign => \json_encode( $data ) ) );
        $reids->expire( $rkey, \Lib\Consts::EXPIRE_30DAY );

        $this->_token = $token;

        return true;
    }

    /**
     * 根据签名校验token
     *
     * @params string $token
     * @params array $params
     * @return boolean
     */
    public function valid( $token, array $params = [ ] ) {
        $rkey = \Lib\Consts::TOKEN_KEY;
        $sign = $this->signature( $token, $params );
        $data = $this->getRedis()->hMget( $rkey, array( $sign ) );
        $pass = false;

        if ( !empty( $data[ $sign ] ) ) {
            $data = \json_decode( $data[ $sign ], true );

            if ( JSON_ERROR_NONE === json_last_error() && is_array( $data ) ) {
                $this->_std = new \Lib\Std( $data );
                $pass       = true;
            }
        }

        return $pass;
    }

    /**
     * signature
     *
     * @param string $pubKey
     * @param array  $params
     * @return string
     */
    public function signature($pubKey, array $params, $priKey = null) {
        ksort($params);

        $signArr = [];

        foreach ( $params as $key => $name ) {
            array_push( $signArr, implode( [ $key, $name ] ) );
        }
        
        if(empty($priKey)) {
            $priKey = \Yaf\Registry::get('config')->get('resource.signature.prikey');
        }

        array_push($signArr, $priKey);

        return sha1( $pubKey . implode( $signArr ) );
    }

    /**
     * 获取Redis
     *
     * @return \Redis
     */
    protected function getRedis() {
        return \Yaf\Registry::get( 'redis' );
    }

    /**
     * @param       $token
     * @param array $params
     * @return bool
     */
    public function delete( $token, array $params = [ ] ) {
        $redis = $this->getRedis();
        $rkey  = \Lib\Consts::TOKEN_KEY;
        $sign  = $this->signature( $token, $params );
        $redis->hDel( $rkey, $sign );

        return !!$token;
    }
}

